#include <QCoreApplication>
#include <QFileInfo>
#include <QFile>
#include <QDir>
#include <QTextCodec>
#include <QRegularExpression>
#include <shared_mutex>

#ifdef Q_OS_WIN
#include <Windows.h>
#else
#include <unistd.h>
#endif

#include "INCLUDE/SettingsUtils.h"
#include "INCLUDE/AnsiConverter.h"
#include "INCLUDE/KSettings.h"
#include "INCLUDE/FileUtils.h"
#include "INCLUDE/LEGACYREPLACER.HPP"

std::shared_mutex mtx;
std::unique_ptr<KSettings> settings_ptr;

QString getCurrentModuleName()
{
#ifdef Q_OS_WIN
    wchar_t result[1024] = {0};
    GetModuleFileNameW(nullptr, result, _countof(result));
    return QString::fromWCharArray(result);
#else
    char result[1024] = {0};
    readlink("/proc/self/exe", result, _countof(result));
    return toQtStr(result);
#endif
}

void initSetings()
{
    std::unique_lock lock(mtx);

    if (settings_ptr == nullptr)
    {
        QString path = QCoreApplication::applicationFilePath();
        if (path.isEmpty())
            path = getCurrentModuleName();

        const QFileInfo fileInfo(path);
        const QString ini_file_name = fileInfo.completeBaseName() + QLatin1String(".ini");

        QString ini_fn = fullNameExistingCase(fileInfo.absolutePath(), ini_file_name);

        getIniFileName(&ini_fn);

        settings_ptr = std::make_unique<KSettings>(ini_fn);
    }
}

const QString& getIniFileName(QString *p_ini_file_name)
{
    static QString iniFileName;

    if (p_ini_file_name == nullptr)
    {
        for (int i = 0; i < 3; ++i)
        {
            {
                std::shared_lock lock(mtx);

                if (settings_ptr != nullptr)
                    return iniFileName;
            }
            initSetings();
        }
    }
    else
    {
        iniFileName = *p_ini_file_name;
    }

    return iniFileName;
}

const KSettings& getSettings()
{
    for (int i = 0; i < 3; ++i)
    {
        {
            std::shared_lock lock(mtx);

            if (settings_ptr != nullptr)
                return *settings_ptr;
        }
        initSetings();
    }

    return *settings_ptr;
}

unsigned int GetPrivateProfileIntA(
    const char *lpAppName,
    const char *lpKeyName,
    int nDefault,
    const KSettings &settings)
{
    const QString default_str = QString::number(nDefault);

    const QString &str = settings.value(toQtStr(lpAppName), toQtStr(lpKeyName), default_str);

    static const QRegularExpression re("([+-]?\\d+)");
    QRegularExpressionMatch match = re.match(str);
    if (match.hasMatch())
        return match.captured(1).toInt();
    else
        return nDefault;
}

unsigned int GetPrivateProfileStringA(
    const char * lpAppName,
    const char * lpKeyName,
    const char * lpDefault,
    char * lpReturnedString,
    unsigned int nSize,
    const KSettings &settings
    )
{
    const QString default_str = toQtStr(lpDefault);

    const QString &str = settings.value(toQtStr(lpAppName), toQtStr(lpKeyName), default_str);

    fromQtStr(str,lpReturnedString, ConvType::ToCp1251);

    return str.length();
}
